package com.atguigu.tingshu.payment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.HttpClient;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.order.client.OrderInfoClientFeign;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;


@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

	@Autowired
	private PaymentInfoService paymentInfoService;

	@Autowired
	private RedissonClient redissonClient;

	@Autowired
	private OrderInfoClientFeign orderInfoClientFeign;

	//从配置文件取值
	@Value("${appid}")
	private String appid;
	@Value("${partner}")
	private String partner;
	@Value("${partnerkey}")
	private String partnerkey;
	@Value("${notifyUrl}")
	private String notifyUrl;

	/**
	 * 找微信服务器申请 支付二维码
	 * @return
	 */
	@SneakyThrows
	@Override
	public String getPayInfoFromWx(@RequestParam Map<String,String> params) {

		Map<String,String> param = new HashMap<>();
		//获取请求地址
		String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		//包装参数
		//获取公众账号ID
		param.put("appid",appid);
		//获取请商户号
		param.put("mch_id",partner);
		//获取随机字符串
		param.put("nonce_str", WXPayUtil.generateNonceStr());
		//获取商品描述
		param.put("body",params.get("desc"));
		//获取请求商户订单号
		param.put("out_trade_no",params.get("orderNo"));
		//获取标价金额
		param.put("total_fee",new BigDecimal(params.get("money")).multiply(new BigDecimal(100)).intValue()+"");
		//获取终端IP
		param.put("spbill_create_ip","192.168.200.1");
		//获取通知地址
		param.put("notify_url",notifyUrl);
		//获取交易类型
		param.put("trade_type","NATIVE");
		//构建附加数据
		Map<String,String> addparam = new HashMap<>();
		addparam.put("exchange",params.get("exchange"));
		addparam.put("routingKey",params.get("routingKey"));
		param.put("attach",JSONObject.toJSONString(addparam));
		//生成签名
		String signedXml = WXPayUtil.generateSignedXml(param, partnerkey);

		//发起请求
		HttpClient httpClient = new HttpClient(url);
		httpClient.setHttps(true);
		httpClient.setXmlParam(signedXml);
		httpClient.post();
		//解析结果
		String content = httpClient.getContent();
		//将结果转换为map
		Map<String, String> result = WXPayUtil.xmlToMap(content);
		//查看响应结果
		if (result.get("return_code").equals("SUCCESS") && result.get("result_code").equals("SUCCESS")){

			Long userId = AuthContextHolder.getUserId();
			//记录本次交易流水
			CompletableFuture.runAsync(()->{
				savePaymentInfo(params,userId);
			});
			//返回支付二维码
			return result.get("code_url");
		}
		//请求失败，记录日志
		log.error("订单No："+params.get("orderNo")+"申请支付地址失败，失败原因为："+result);
		return null;
	}

	private void savePaymentInfo(Map<String, String> params, Long userId) {
		PaymentInfo paymentInfo = new PaymentInfo();
		paymentInfo.setUserId(userId);
		paymentInfo.setPaymentType(params.get("type"));//订单
		paymentInfo.setOrderNo(params.get("orderNo"));
		paymentInfo.setAmount(new BigDecimal(params.get("money")));
		paymentInfo.setContent(params.get("desc"));
		paymentInfo.setPaymentStatus("1401");
		paymentInfo.setPayWay("1101");
		//保存
		paymentInfoService.save(paymentInfo);

	}

	/**
	 * 查询支付订单的结果，主动查询，兜底
	 * @param orderNo
	 * @return
	 */
	@SneakyThrows
	@Override
	public String getOrderPayResult(String orderNo) {
		//请求url
		String url = "https://api.mch.weixin.qq.com/pay/orderquery";
		//包装参数
		Map<String,String> param = new HashMap<>();
		param.put("appid",appid);
		param.put("mch_id",partner);
		param.put("out_trade_no",orderNo);
		param.put("nonce_str",WXPayUtil.generateNonceStr());
		//生成签名
		String signedXml = WXPayUtil.generateSignedXml(param, partnerkey);
		//创建Http构造器,发起请求
		HttpClient httpClient = new HttpClient(url);
		httpClient.setHttps(true);
		httpClient.setXmlParam(signedXml);
		httpClient.post();
		//获取支付响应码
		int statusCode = httpClient.getStatusCode();
		//获取结果
		String content = httpClient.getContent();
		//将结果转换为map
		Map<String, String> result = WXPayUtil.xmlToMap(content);
		//查看响应结果
		if (result.get("return_code").equals("SUCCESS") &&
				result.get("result_code").equals("SUCCESS")&&
				result.get("trade_state").equals("SUCCESS")){
			////TODO-在已支付的情况下修改paymentInfo(未支付的数据)
			PaymentInfo paymentInfo = paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>()
					.eq(PaymentInfo::getOrderNo, orderNo)
					.eq(PaymentInfo::getPaymentStatus, "1401"));
			if (paymentInfo != null){
				//修改支付状态为已支付
				paymentInfo.setPaymentStatus("1402");
				paymentInfo.setOutTradeNo(result.get("transaction_id"));
				//写进数据库
				paymentInfoService.updateById(paymentInfo);
			}
			return result.get("trade_state");
		}
		//失败返回整个消息
		return JSONObject.toJSONString(result);
	}

	/**
	 * 根据微信返回的支付结果，修改流水记录
	 * @param result
	 */
	@Override
	public void updatePaymentInfo(Map<String, String> result) {
		//获取本次支付的订单号
		String outTradeNo = result.get("out_trade_no");
		//加锁
		RLock lock = redissonClient.getLock("paymentInfo_lock_" + outTradeNo);
		lock.lock();
		try {
			PaymentInfo paymentInfo = paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo, outTradeNo));
			//获取本次支付的流水号
			String transactionId = result.get("transaction_id");
			if (paymentInfo.getPaymentStatus().equals("1401")){
				//未支付
				paymentInfo.setPaymentStatus("1402");//修改为已支付
				paymentInfo.setOutTradeNo(transactionId);
				paymentInfo.setCallbackTime(new Date());
				paymentInfo.setCallbackContent(JSONObject.toJSONString(result));
				String paymentType = paymentInfo.getPaymentType();
				switch (paymentType){
					case "1301" ->{
						String type = "订单";
						//TODO-支付成功后，需要通user模块，增加用户购买的专辑数量，或者开通会员或续期
						//TODO-支付成功后，需要seach模块专辑的热度增加
						//TODO-支付成功后，需要order模块记录本次交易
					}
					case "1302" ->{
						String type =  "充值";
						//TODO-充值成功，通知账号微服务
					}
				}
			}else {
				//同一笔订单不同的付款流水
				if (paymentInfo.getOutTradeNo().equals(transactionId)){
					//说明多付了
					System.out.println("退款");
				}
			}
		}catch (Exception e){
			//付款失败情况
			log.error("订单付款失败，订单号：("+outTradeNo+"失败原因："+result);
		}finally {
			lock.unlock();
		}
	}


}
